<template>

  <!--头: 引入 CommonHead 子组件-->
  <header class="play-video-head">
    <CommonHead title="观看已购买的视频"/>
  </header>

  <!--体: 播放视频-->
  <section class="play-video-body">

    <!--当前正在播放的集的标题-->
    <h4 class="episode-title" v-if="video['chapters'] && video['chapters'].length > 0">
      当前播放: {{ currentEpisode["episodeTitle"] }}
    </h4>

    <!--西瓜视频播放器容器: 不要在父容器中设置v-if标签-->
    <article id="videoContent" class="video-content"/>

    <br/>

    <!--当视频存在章集数据时展示-->
    <div v-if="video['chapters'] && video['chapters'].length > 0">

      <!--发送弹幕的相关控件-->
      <van-cell-group inset>

        <!--弹幕控件: 双绑弹幕内容，垂直居中，可清除，背景提示字，单绑禁用标记，关闭提示-->
        <van-field v-model="danMuText" center clearable placeholder="请输入弹幕内容"
                   :disabled="danMuControlsDisabled" autocomplete="off">

          <template #button>
            <van-button size="small" type="primary" :disabled="danMuControlsDisabled" @click="sendDanMu">
              发送弹幕
            </van-button>
          </template>

        </van-field>
      </van-cell-group>

      <!--视频章集列表标题-->
      <van-divider>章集列表</van-divider>

      <!--遍历chapters-->
      <article v-for="(chapter, chapterIndex) in video['chapters']" :key="chapter['chapterId']"
               class="chapters-content">

        <!--单元格: 章标题-->
        <van-cell-group :title="'CH' + index((chapterIndex + 1)) + '. ' + chapter['chapterTitle']">

          <!--单元格项: 遍历episodes-->
          <van-cell v-for="(episode, episodeIndex) in chapter['episodes']" center :key="episode['episodeId']"
                    :title="'EP' + index((episodeIndex + 1)) + '. ' + episode['episodeTitle']"
                    @click="changeEpisode(episode)">

            <!--章描述: 使用文本省略-->
            <template #label>
              <!--文本省略: 章描述，展示1行，显示展开和收起按钮-->
              <van-text-ellipsis :content="episode['episodeInfo']" rows="1" expand-text="展开" collapse-text="收起"/>
            </template>

            <!--展示当前播放标签-->
            <template #value>
              <!--整合视频的第一集添加免费标签-->
              <van-tag v-if="currentEpisode['episodeId'] === episode['episodeId']" type="primary">
                当前播放
              </van-tag>
            </template>

          </van-cell>
        </van-cell-group>
      </article>
    </div>

    <!--当视频不存在章集数据时展示-->
    <div v-else>
      <h4>该视频暂无章集列表，请联系运维人员</h4>
    </div>

  </section>

</template>

<script setup>
import CommonHead from "@/components/CommonHead";
import {SELECT_BY_VIDEO_ID} from "@/api/video";
import {MINIO_HOST, LESSON_WEBSOCKET_HOST, SUCCESS, randomStr} from "@/constant";
import XGPlayer from 'xgplayer';
import router from "@/router";
import {useStore} from 'vuex';
import {onBeforeMount, shallowRef, computed, shallowReactive} from "vue";
import {showFailToast} from "vant";

/* ==================== data ==================== */

// data: Vuex实例，直接使用useStore()会报错
let vuex = useStore();

// data: 西瓜视频播放器实例，WebSocket实例
let xgPlayer = null, webSocket = null;

// data: 从当前路由地址中获取视频表主键
const videoId = router.currentRoute.value.query['videoId'];

// data: 发送的弹幕内容
let danMuText = shallowRef('');

// data: 是否禁用弹幕相关控件，未播放时不允许发弹幕，已播放时允许发弹幕
let danMuControlsDisabled = shallowRef(true);

// data: 视频对象
let video = shallowRef({});

// data: 当前播放的集对象
let currentEpisode = shallowReactive({'episodeId': 0, 'episodeUrl': '', 'episodeTitle': ''});

/* ==================== computed ==================== */

// computed: 计算索引，将小于10的索引补充 "0" 作为前缀
let index = computed(() => index => index < 10 ? "0" + index : "" + index);

/* ==================== method ==================== */

// method: 按视频表主键查询视频记录
async function selectByVideoId(videoId) {

  // 异步调用根据视频主键查询视频详情的接口
  let result = await SELECT_BY_VIDEO_ID(videoId);
  let resp = result['data'];
  if (resp.code === SUCCESS) {
    let data = resp.data;
    video.value = data;

    // 若该视频中存在章集记录，则赋值初始化第一章第一集内容
    if (null !== data['chapters'] && data['chapters'].length > 0) {

      // 获取第一章中的全部集
      let episodes = data['chapters'][0]['episodes'];
      if (null != episodes && episodes.length > 0) {

        // 初始化第一集
        currentEpisode["episodeId"] = episodes[0]["episodeId"];
        currentEpisode["episodeUrl"] = episodes[0]["episodeUrl"];
        currentEpisode["episodeTitle"] = episodes[0]["episodeTitle"];

        // 初始化西瓜视频播放器
        initXgPlayer();
      }
    }
  } else {
    showFailToast(resp.message + ': ' + resp.data);
  }
}

// method: 初始化视频播放器
function initXgPlayer() {

  // 创建西瓜视频播放器实例
  xgPlayer = new XGPlayer({
    id: "videoContent", // 视频容器的ID值
    url: MINIO_HOST + '/episode/' + currentEpisode['episodeUrl'], // 视频对象
    poster: MINIO_HOST + '/cover/' + video.value['coverImage'], // 视频封面
    fluid: true, // 使用流体布局
    playbackRate: [0.5, 1, 1.5, 2], // 倍速播放设置
    download: false, // 不允许下载视频
    pip: false, // 不开启画中画
    danmu: {
      comments: [{ // 一条初始欢迎弹幕配置
        id: randomStr(10), // 弹幕唯一标识
        start: 3000, // 弹幕在3秒后出现
        duration: 8000, // 弹幕在8秒后消失
        txt: "前方高能：一大堆弹幕即将来临..", // 弹幕内容
        mode: "scroll", // 弹幕出现方式
        style: {color: 'red', fontSize: '20px', padding: '20px'} // 弹幕样式
      }]
    }
  });

  // 当播放器播放时触发: 禁用发送弹幕的按钮并连接WebSocket服务端
  xgPlayer.on('play', () => {

    // 开启发送弹幕的按钮
    danMuControlsDisabled.value = false;

    // 判断浏览器是否支持WebSocket功能
    if (!WebSocket) {
      showFailToast("您的浏览器不支持WebSocket！")
      return;
    }

    // 使用ws://协议连接WebSocket服务端并传递用户ID参数
    webSocket = new WebSocket(LESSON_WEBSOCKET_HOST + '/danmu/' + sessionStorage.getItem('userId'));

    // 接收到WebSocket服务端消息时时触发
    webSocket.onmessage = resp => {
      let message = JSON.parse(resp.data);

      // 发布用户弹幕到视频播放器上
      xgPlayer.danmu.sendComment({
        id: randomStr(10), // 弹幕唯一标识
        duration: 8000, // 弹幕在8秒后消失
        txt: message, // 弹幕内容
        mode: "scroll", // 弹幕出现方式
      });

      // 弹幕输入控件清空
      danMuText.value = "";
    };
  });

  // 当播放器暂停时触发: 禁用发送弹幕的按钮
  xgPlayer.on('pause', () => danMuControlsDisabled.value = true);

  // 当播放器结束时触发: 断开和WebSocket服务端的通信
  xgPlayer.on('ended', () => webSocket.close());
}

// method: 发送弹幕到WebSocket服务器
function sendDanMu() {

  // 非空校验
  if ('' === danMuText.value) {
    showFailToast("弹幕不能为空！");
    return;
  }

  // 发送弹幕到WebSocket服务端
  webSocket.send(JSON.stringify(danMuText.value));
}

// method: 当点击每一集时，切换播放的视频
function changeEpisode(episode) {

  // 仅在当前视频播放器正在播放时允许切换视频集操作
  if (!xgPlayer['_hasStart']) {
    return;
  }

  // 切换西瓜视频播放器中的 `src` 属性
  xgPlayer.src = MINIO_HOST + '/episode/' + episode['episodeUrl'];

  // 切换当前播放的视频集的地址，标题和主键
  currentEpisode['episodeUrl'] = episode['episodeUrl'];
  currentEpisode['episodeTitle'] = episode['episodeTitle'];
  currentEpisode['episodeId'] = episode['episodeId'];

  // 播放器重新播放
  xgPlayer.replay();
}

/* ==================== beforeMount ==================== */

// beforeMount: DOM挂载前，判断用户是否登录
onBeforeMount(() => {
  if (!vuex.state['loginFlag']) {
    showFailToast('请先登录');
    setTimeout(() => router.push("/LoginByAccount"), 1000);
  } else {
    // 按视频表主键查询视频记录
    selectByVideoId(videoId);
  }
});
</script>

<style scoped lang="scss">

.play-video-body {

  /**章集列表容器*/
  .chapters-content {
    text-align: left; // 内容居左
  }
}

</style>